import os
import json
import uuid
import logging
import requests
from django.conf import settings
from django.utils import timezone
from django.db import connection
from .models import ChatSession, ChatMessage

logger = logging.getLogger(__name__)

class ChatbotService:
    """聊天机器人服务类"""
    
    # 添加与系统相关的关键词列表
    SYSTEM_RELATED_KEYWORDS = [
        "盲盒", "订单", "商品", "超市", "支付", "价格", "物流", "配送", "退款", 
        "积分", "优惠", "活动", "会员", "购买", "开盒", "推荐", "分类", "收藏",
        "库存", "销量", "评价", "评论", "购物车", "账户", "登录", "注册", "密码"
    ]
    
    def __init__(self):
        self.api_key = settings.DEEPSEEK_API_KEY
        self.api_url = "https://api.deepseek.com/v1/chat/completions"
        self.headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {self.api_key}"
        }
        # 基础系统提示词，用于指导AI扮演客服角色
        self.base_system_prompt = """
        你是一个专业的盲盒电商网站智能客服，名叫"妙趣AI助手"。你的职责是帮助用户解答关于盲盒产品、订单、物流、退换货等问题。
        
        请注意以下规则：
        1. 保持友好、礼貌的语气，使用亲切的表达方式
        2. 对于盲盒产品相关问题，提供详细的解答
        3. 对于订单问题，解释订单状态、支付方式等
        4. 对于物流问题，解释发货时间、物流查询方式等
        5. 对于退换货问题，解释政策和流程
        6. 如果无法解答某个问题，诚实地表示并建议用户联系人工客服
        7. 回答要简洁明了，不要过长
        8. 如果用户连续问5次与本系统无关的问题，请委婉提醒用户回到与盲盒商城相关的话题
        
        回复应当简短且友好，不超过100字。
        """
        
        # 初始化会话无关话题计数器字典
        self.off_topic_counters = {}
    
    def get_user_data(self, user_id):
        """获取用户相关数据，包括订单和盲盒信息"""
        if not user_id:
            return None
            
        user_data = {
            "orders": [],
            "blind_boxes": []
        }
        
        # 获取用户订单数据
        try:
            with connection.cursor() as cursor:
                cursor.execute("""
                    SELECT 
                        o.order_id, o.order_no, o.total_amount, o.status, o.create_time,
                        p.pay_method, p.pay_time
                    FROM tb_order o
                    LEFT JOIN tb_payment p ON o.order_id = p.order_id
                    WHERE o.user_id = %s
                    ORDER BY o.create_time DESC
                    LIMIT 5
                """, [user_id])
                
                orders = self.dictfetchall(cursor)
                
                # 获取订单状态中文描述
                status_map = {
                    '0': '待支付',
                    '1': '已支付',
                    '2': '已发货',
                    '3': '已收货',
                    '4': '已完成',
                    '5': '已取消',
                    '6': '已退款'
                }
                
                # 格式化订单数据
                for order in orders:
                    order['status_text'] = status_map.get(str(order['status']), '未知状态')
                    
                    # 获取订单包含的盲盒
                    cursor.execute("""
                        SELECT 
                            oi.item_id, oi.box_id, oi.quantity, oi.price,
                            b.title as box_name, b.price as original_price
                        FROM tb_order_item oi
                        INNER JOIN tb_blind_box b ON oi.box_id = b.box_id
                        WHERE oi.order_id = %s
                    """, [order['order_id']])
                    
                    order['items'] = self.dictfetchall(cursor)
                    user_data['orders'].append(order)
                
                # 获取用户拥有的盲盒
                cursor.execute("""
                    SELECT 
                        o.order_id, o.order_no, o.status, o.create_time,
                        oi.box_id, b.title as box_name, b.price
                    FROM tb_order o
                    INNER JOIN tb_order_item oi ON o.order_id = oi.order_id
                    INNER JOIN tb_blind_box b ON oi.box_id = b.box_id
                    WHERE o.user_id = %s AND o.status IN (3, 4)
                    ORDER BY o.create_time DESC
                    LIMIT 10
                """, [user_id])
                
                user_data['blind_boxes'] = self.dictfetchall(cursor)
                
                # 获取用户基本信息
                cursor.execute("""
                    SELECT username, email, phone, create_time
                    FROM tb_user
                    WHERE id = %s
                """, [user_id])
                
                user_info = self.dictfetchall(cursor)
                if user_info:
                    user_data['user_info'] = user_info[0]
                
            return user_data
        except Exception as e:
            logger.exception(f"获取用户数据失败: {str(e)}")
            return None
    
    def dictfetchall(self, cursor):
        """将游标返回的结果转换为字典列表"""
        columns = [col[0] for col in cursor.description]
        return [dict(zip(columns, row)) for row in cursor.fetchall()]
    
    def format_user_data_for_prompt(self, user_data):
        """将用户数据格式化为系统提示"""
        if not user_data:
            return ""
            
        prompt = "\n\n以下是用户的个人数据，你可以参考这些信息来回答用户的问题:\n\n"
        
        # 添加用户基本信息
        if 'user_info' in user_data:
            user_info = user_data['user_info']
            prompt += f"用户信息: 用户名 {user_info.get('username', '未知')}, "
            prompt += f"注册时间 {user_info.get('create_time', '未知')}\n\n"
        
        # 添加订单信息
        if user_data['orders']:
            prompt += "最近的订单:\n"
            for idx, order in enumerate(user_data['orders'], 1):
                prompt += f"{idx}. 订单号: {order.get('order_no', '未知')}, "
                prompt += f"状态: {order.get('status_text', '未知')}, "
                prompt += f"金额: {order.get('total_amount', '0')}元, "
                prompt += f"创建时间: {order.get('create_time', '未知')}\n"
                
                if order.get('items'):
                    prompt += "   包含的盲盒:\n"
                    for item in order['items']:
                        prompt += f"   - {item.get('box_name', '未知盲盒')} x{item.get('quantity', 1)}, "
                        prompt += f"单价: {item.get('price', '0')}元\n"
            prompt += "\n"
        
        # 添加盲盒信息
        if user_data['blind_boxes']:
            prompt += "用户拥有的盲盒:\n"
            for idx, box in enumerate(user_data['blind_boxes'], 1):
                prompt += f"{idx}. {box.get('box_name', '未知盲盒')}, "
                prompt += f"价格: {box.get('price', '0')}元, "
                prompt += f"购买于: {box.get('create_time', '未知')}\n"
            prompt += "\n"
        
        prompt += "请根据以上用户数据，为用户提供更加个性化和精确的回答。"
        return prompt
    
    def get_all_blind_boxes(self):
        """获取系统中所有的盲盒数据"""
        all_boxes = []
        
        try:
            with connection.cursor() as cursor:
                cursor.execute("""
                    SELECT 
                        b.box_id, b.title, b.price, b.description, b.stock,
                        b.sales, b.category_id, c.name as category_name,
                        m.name as market_name
                    FROM tb_blind_box b
                    LEFT JOIN tb_category c ON b.category_id = c.category_id
                    LEFT JOIN tb_market m ON b.market_id = m.market_id
                    WHERE b.is_active = 1
                    ORDER BY b.sales DESC
                    LIMIT 30
                """)
                
                all_boxes = self.dictfetchall(cursor)
                
                # 获取盲盒可能包含的商品类型
                for box in all_boxes:
                    cursor.execute("""
                        SELECT p.product_id, p.name, p.description
                        FROM tb_product p
                        INNER JOIN tb_box_product bp ON p.product_id = bp.product_id
                        WHERE bp.box_id = %s
                        LIMIT 5
                    """, [box['box_id']])
                    
                    box['possible_products'] = self.dictfetchall(cursor)
        
        except Exception as e:
            logger.exception(f"获取所有盲盒数据失败: {str(e)}")
        
        return all_boxes

    def format_all_boxes_for_prompt(self, all_boxes):
        """将所有盲盒数据格式化为系统提示"""
        if not all_boxes:
            return ""
        
        prompt = "\n\n商城现有盲盒信息:\n\n"
        
        for idx, box in enumerate(all_boxes, 1):
            prompt += f"{idx}. {box.get('title', '未知盲盒')} - {box.get('price', '0')}元\n"
            prompt += f"   分类: {box.get('category_name', '未分类')}, 来自: {box.get('market_name', '未知超市')}\n"
            prompt += f"   简介: {box.get('description', '无描述')[:100]}...\n"
            
            if box.get('possible_products'):
                prompt += "   可能包含的商品: "
                products = [p.get('name', '未知商品') for p in box['possible_products']]
                prompt += ", ".join(products) + "\n"
            
            prompt += "\n"
        
        return prompt

    def get_system_prompt(self, user_id):
        """获取包含用户数据和系统数据的系统提示词"""
        system_prompt = self.base_system_prompt
        
        # 获取系统中所有盲盒信息
        all_boxes = self.get_all_blind_boxes()
        if all_boxes:
            all_boxes_prompt = self.format_all_boxes_for_prompt(all_boxes)
            system_prompt += all_boxes_prompt
        
        # 如果有用户ID，添加用户数据
        if user_id:
            user_data = self.get_user_data(user_id)
            if user_data:
                user_data_prompt = self.format_user_data_for_prompt(user_data)
                system_prompt += user_data_prompt
        
        return system_prompt
    
    def create_or_get_session(self, session_id=None, user_id=None):
        """创建或获取会话"""
        if session_id:
            try:
                session = ChatSession.objects.get(session_id=session_id)
                # 更新最后活动时间
                session.last_activity = timezone.now()
                session.save()
                return session
            except ChatSession.DoesNotExist:
                pass
        
        # 创建新会话
        new_session_id = session_id or str(uuid.uuid4())
        session = ChatSession(
            session_id=new_session_id,
            user_id=user_id,
            start_time=timezone.now(),
            last_activity=timezone.now(),
            is_active=True
        )
        session.save()
        
        # 获取系统提示词(包含用户数据)
        system_prompt = self.get_system_prompt(user_id)
        
        # 创建系统消息作为会话的第一条消息
        ChatMessage.objects.create(
            session_id=session,
            role="system",
            content=system_prompt,
            timestamp=timezone.now()
        )
        
        return session
    
    def add_message(self, session, role, content):
        """添加消息到会话"""
        message = ChatMessage.objects.create(
            session_id=session,
            role=role,
            content=content,
            timestamp=timezone.now()
        )
        # 更新会话的最后活动时间
        session.last_activity = timezone.now()
        session.save()
        return message
    
    def get_message_history(self, session, limit=10):
        """获取会话历史消息"""
        # 获取除系统消息外的最近的消息
        messages = ChatMessage.objects.filter(
            session_id=session
        ).exclude(
            role="system"
        ).order_by('-timestamp')[:limit]
        
        # 反转消息顺序，以便按时间顺序排列
        return list(reversed(messages))
    
    def format_messages_for_api(self, session):
        """格式化消息用于API请求"""
        # 获取系统消息
        system_message = ChatMessage.objects.filter(
            session_id=session,
            role="system"
        ).first()
        
        api_messages = []
        
        # 添加系统消息
        if system_message:
            api_messages.append({
                "role": "system",
                "content": system_message.content
            })
        
        # 获取用户和助手的消息历史（最多5条对话，10条消息）
        user_assistant_messages = self.get_message_history(session, limit=10)
        
        for message in user_assistant_messages:
            api_messages.append({
                "role": message.role,
                "content": message.content
            })
        
        return api_messages
    
    def is_system_related(self, message):
        """判断消息是否与系统相关"""
        message = message.lower()
        
        # 检查是否包含系统相关关键词
        for keyword in self.SYSTEM_RELATED_KEYWORDS:
            if keyword in message:
                return True
        
        return False
    
    def update_off_topic_counter(self, session_id, message):
        """更新无关话题计数器，如果消息相关则重置计数"""
        # 如果会话ID不在计数器中，初始化
        if session_id not in self.off_topic_counters:
            self.off_topic_counters[session_id] = 0
        
        # 检查消息是否与系统相关
        if self.is_system_related(message):
            # 如果相关，重置计数
            self.off_topic_counters[session_id] = 0
            return 0
        else:
            # 如果不相关，增加计数
            self.off_topic_counters[session_id] += 1
            return self.off_topic_counters[session_id]
    
    def get_off_topic_response(self, counter):
        """根据无关话题计数器获取响应"""
        if counter >= 5:
            return ("非常抱歉，我作为盲盒商城的客服助手，主要职责是解答与盲盒商品、订单、物流等相关的问题。"
                    "为了给您提供更好的服务，请问您有什么关于我们商城或产品的问题吗？"
                    "我很乐意为您介绍我们的热门盲盒或帮您查询订单状态。")
        elif counter >= 3:
            return ("我注意到您的问题可能与本盲盒商城业务不太相关。作为商城客服，我可能无法提供很专业的回答。"
                    "有什么关于我们盲盒、订单或服务的问题，我很乐意为您解答。")
        else:
            return None  # 返回None表示不需要特殊回复

    def get_response(self, session, user_message):
        """获取AI响应"""
        # 添加用户消息到会话
        self.add_message(session, "user", user_message)
        
        # 更新无关话题计数器
        off_topic_count = self.update_off_topic_counter(session.session_id, user_message)
        
        # 如果连续提问无关话题达到阈值，给出特定回复
        off_topic_response = self.get_off_topic_response(off_topic_count)
        if off_topic_response and off_topic_count >= 5:
            self.add_message(session, "assistant", off_topic_response)
            return off_topic_response
        
        # 如果API密钥为空，返回模拟响应
        if not self.api_key or self.api_key == 'sk-*****' or self.api_key == '':
            logger.warning("未设置有效的API密钥，返回模拟响应")
            # 根据用户消息生成简单的模拟响应
            mock_responses = {
                "你好": "您好！我是妙趣拾光锦盒的AI客服助手，很高兴为您服务！请问有什么我可以帮您的吗？",
                "介绍": "妙趣拾光锦盒是一家专注于超市盲盒的电商平台，我们致力于减少食物浪费，为用户提供优质实惠的商品。",
                "盲盒": "我们的盲盒包含各种超市商品，每个盲盒都是惊喜！您可以在首页浏览我们的盲盒商品，或者使用智能推荐系统找到适合您的产品。",
                "订单": '您可以在"我的订单"页面查看您的所有订单状态。如果有任何问题，可以随时联系我们的客服。',
                "配送": '我们的商品一般在下单后1-3天内发出，请耐心等待。您可以在订单详情页查看物流信息。',
                "退款": '如果您对商品不满意，可以在收到商品7天内申请退款。具体政策请查看"帮助中心"的"退款政策"。'
            }
            
            # 如果有无关话题提醒，混合到模拟响应中
            if off_topic_response and off_topic_count >= 3 and off_topic_count < 5:
                # 对于3-4次无关问题，给出轻微提醒但仍尝试回答
                custom_response = off_topic_response
                self.add_message(session, "assistant", custom_response)
                return custom_response
            
            # 查询盲盒信息的请求
            if "盲盒列表" in user_message or "所有盲盒" in user_message or "有哪些盲盒" in user_message:
                all_boxes = self.get_all_blind_boxes()
                if all_boxes:
                    boxes_text = "商城现有以下热门盲盒：\n"
                    for idx, box in enumerate(all_boxes[:10], 1):  # 只展示前10个热门盲盒
                        boxes_text += f"{idx}. {box.get('title')} - {box.get('price')}元, 分类: {box.get('category_name')}\n"
                    self.add_message(session, "assistant", boxes_text)
                    return boxes_text

            # 查询具体盲盒信息
            if "盲盒详情" in user_message or "介绍一下" in user_message:
                all_boxes = self.get_all_blind_boxes()
                if all_boxes:
                    # 尝试查找用户询问的具体盲盒
                    for box in all_boxes:
                        if box.get('title', '') in user_message:
                            box_detail = f"盲盒详情: {box.get('title')}\n"
                            box_detail += f"价格: {box.get('price')}元\n"
                            box_detail += f"分类: {box.get('category_name')}\n"
                            box_detail += f"来自: {box.get('market_name')}\n"
                            box_detail += f"简介: {box.get('description')}\n"
                            
                            if box.get('possible_products'):
                                box_detail += "可能包含的商品: "
                                products = [p.get('name', '未知商品') for p in box['possible_products']]
                                box_detail += ", ".join(products)
                            
                            self.add_message(session, "assistant", box_detail)
                            return box_detail
                    
                    # 没有找到具体盲盒，返回推荐
                    boxes_text = "抱歉，没有找到您询问的具体盲盒。这里是一些热门盲盒推荐：\n"
                    for idx, box in enumerate(all_boxes[:5], 1):  # 只展示前5个热门盲盒
                        boxes_text += f"{idx}. {box.get('title')} - {box.get('price')}元\n"
                    self.add_message(session, "assistant", boxes_text)
                    return boxes_text
            
            # 尝试查询用户的订单信息
            if session.user_id and ("我的订单" in user_message or "订单" in user_message):
                user_data = self.get_user_data(session.user_id)
                if user_data and user_data['orders']:
                    orders_text = "以下是您的最近订单信息：\n"
                    for idx, order in enumerate(user_data['orders'], 1):
                        orders_text += f"{idx}. 订单号: {order.get('order_no')}, 状态: {order.get('status_text')}, 金额: {order.get('total_amount')}元\n"
                    self.add_message(session, "assistant", orders_text)
                    return orders_text
            
            # 尝试查询用户的盲盒信息
            if session.user_id and ("我的盲盒" in user_message or "盲盒" in user_message):
                user_data = self.get_user_data(session.user_id)
                if user_data and user_data['blind_boxes']:
                    boxes_text = "以下是您拥有的盲盒：\n"
                    for idx, box in enumerate(user_data['blind_boxes'], 1):
                        boxes_text += f"{idx}. {box.get('box_name')}, 购买于 {box.get('create_time')}\n"
                    self.add_message(session, "assistant", boxes_text)
                    return boxes_text
            
            # 简单匹配用户消息中的关键词
            response = "感谢您的咨询！我是妙趣拾光锦盒的AI助手。很抱歉，我暂时无法连接到AI服务。请问有什么我可以帮助您的吗？"
            for keyword, reply in mock_responses.items():
                if keyword in user_message:
                    response = reply
                    break
            
            # 保存模拟的AI响应到会话
            self.add_message(session, "assistant", response)
            return response
        
        # 准备发送给API的消息
        messages = self.format_messages_for_api(session)
        
        # 添加关于话题限制的额外提示(如果需要)
        if off_topic_count >= 3:
            messages.append({
                "role": "system",
                "content": ("用户已经连续提出多个与盲盒商城无关的问题。请委婉地提醒用户回到与商城相关的话题，"
                          "同时尽量简短地回答当前问题，然后引导用户询问盲盒、订单或商城服务相关的问题。")
            })
        
        # 准备请求数据
        data = {
            "model": "deepseek-chat",
            "messages": messages,
            "temperature": 0.7,
            "max_tokens": 800
        }
        
        try:
            # 发送请求到DeepSeek API
            response = requests.post(
                self.api_url,
                headers=self.headers,
                data=json.dumps(data),
                timeout=30
            )
            
            # 检查响应状态
            if response.status_code == 200:
                response_data = response.json()
                ai_message = response_data['choices'][0]['message']['content']
                
                # 如果有无关话题提醒且计数达到5，直接使用预设回复
                if off_topic_response and off_topic_count >= 5:
                    ai_message = off_topic_response
                
                # 保存AI响应到会话
                self.add_message(session, "assistant", ai_message)
                return ai_message
            else:
                logger.error(f"API请求失败: {response.status_code} - {response.text}")
                error_message = "抱歉，我遇到了一些技术问题。请稍后再试或联系客服。"
                self.add_message(session, "assistant", error_message)
                return error_message
                
        except Exception as e:
            logger.exception(f"获取AI响应时出错: {str(e)}")
            error_message = "抱歉，我遇到了一些技术问题。请稍后再试或联系客服。"
            self.add_message(session, "assistant", error_message)
            return error_message 